<script setup lang="ts">
import {Group, Mesh, RepeatWrapping} from 'three'

import {useSeek, useTexture} from "@tresjs/core";

import * as ConfigApi from '@/api/infra/config'
import {ThemeApi, ThemeVO} from '@/api/pb/theme'

import { DefaultWallMaterialConfigKey, DefaultWallType, WallType } from '@/types/web3d'
import {ResourceContentVO} from "@/api/resource/content";

const message = useMessage()
const {seekByName} = useSeek()

const show = defineModel<boolean>()

const loading = ref(false)

// 默认网格大小
const gridSideLength = inject<number>('gridSideLength')!

// 主题数据
const theme = inject<Ref<ThemeVO>>('theme')!
// 实际大小，长 宽 高
// 2D和3D不同，length -> w，width -> h
const length = gridSideLength * theme.value.grid.w
const width = gridSideLength * theme.value.grid.h

// 墙体 Group
const wallGroup = inject<Group>('wallGroup')!

// 默认纹理
const defaultTexture = ref({
  bottom: '',
  side: '',
  top: ''
})
// 当前纹理
const currentTexture = ref<{
  bottom?: string,
  top?: string,
  front?: string,
  back?: string,
  left?: string,
  right?: string,
}>({...theme.value!.modelMeta?.wallsMaterial})

const defaultItemList = ref([
  {
    data: computed({
      get: () => defaultTexture.value.bottom,
      set: (url) => defaultTexture.value.bottom = url
    }),
    type: DefaultWallType.BOTTOM,
    label: '底部',
  },
  {
    data: computed({
      get: () => defaultTexture.value.side,
      set: (url) => defaultTexture.value.side = url
    }),
    type: DefaultWallType.SIDE,
    label: '侧面',
  },
  {
    data: computed({
      get: () => defaultTexture.value.top,
      set: (url) => defaultTexture.value.top = url
    }),
    type: DefaultWallType.TOP,
    label: '顶部',
  }
])
const currentItemList = ref([
  {
    data: computed({
      get: () => currentTexture.value.bottom,
      set: (url) => currentTexture.value.bottom = url
    }),
    type: WallType.BOTTOM,
    label: '底部',
  },
  {
    data: computed({
      get: () => currentTexture.value.top,
      set: (url) => currentTexture.value.top = url
    }),
    type: WallType.TOP,
    label: '顶部',
  },
  {
    data: computed({
      get: () => currentTexture.value.front,
      set: (url) => currentTexture.value.front = url
    }),
    type: WallType.FRONT,
    label: '正面',
  },
  {
    data: computed({
      get: () => currentTexture.value.back,
      set: (url) => currentTexture.value.back = url
    }),
    type: WallType.BACK,
    label: '背面',
  },
  {
    data: computed({
      get: () => currentTexture.value.left,
      set: (url) => currentTexture.value.left = url
    }),
    type: WallType.LEFT,
    label: '左侧',
  },
  {
    data: computed({
      get: () => currentTexture.value.right,
      set: (url) => currentTexture.value.right = url
    }),
    type: WallType.RIGHT,
    label: '右侧',
  }
])

/** 默认纹理 */
// 获取默认纹理
const getDefaultTexture = async () => {
  const datas = await Promise.all([
    // 地面材质
    ConfigApi.getConfigKey(DefaultWallMaterialConfigKey.BOTTOM),
    // 侧面材质
    ConfigApi.getConfigKey(DefaultWallMaterialConfigKey.SIDE),
    // 顶部材质
    ConfigApi.getConfigKey(DefaultWallMaterialConfigKey.TOP)
  ])

  defaultTexture.value.bottom = datas[0]
  defaultTexture.value.side = datas[1]
  defaultTexture.value.top = datas[2]

  if (!currentTexture.value.bottom) currentTexture.value.bottom = defaultTexture.value.bottom
  if (!currentTexture.value.top) currentTexture.value.top = defaultTexture.value.top
  if (!currentTexture.value.front) currentTexture.value.front = defaultTexture.value.side
  if (!currentTexture.value.back) currentTexture.value.back = defaultTexture.value.side
  if (!currentTexture.value.left) currentTexture.value.left = defaultTexture.value.side
  if (!currentTexture.value.right) currentTexture.value.right = defaultTexture.value.side
}
// 修改默认纹理
const changeDefaultTexture = async (url: string, type: DefaultWallType) => {
  loading.value = true

  const configKey = DefaultWallMaterialConfigKey[type.toUpperCase()]
  const data = await ConfigApi.getConfigDataKey(configKey)
  defaultTexture.value[type] = data.value = url
  await ConfigApi.updateConfig(data)

  loading.value = false

  try {
    // await message.confirm('是否应用至当前纹理', '默认纹理设置成功', 'success')
    loading.value = true

    const wallsMaterial = theme.value?.modelMeta?.wallsMaterial
    if (type === DefaultWallType.BOTTOM) {
      if (!wallsMaterial.bottom) await defaultCoverCurrentTexture(WallType.BOTTOM)
    } else if (type === DefaultWallType.TOP) {
      if (!wallsMaterial.top) await defaultCoverCurrentTexture(WallType.TOP)
    } else {
      if (!wallsMaterial.left) await defaultCoverCurrentTexture(WallType.LEFT)
      if (!wallsMaterial.right) await defaultCoverCurrentTexture(WallType.RIGHT)
      if (!wallsMaterial.front) await defaultCoverCurrentTexture(WallType.FRONT)
      if (!wallsMaterial.back) await defaultCoverCurrentTexture(WallType.BACK)
    }

  } catch (e){
    console.error(e)
  } finally {
    loading.value = false
  }
}

/** 当前纹理 */
// 修改当前纹理
const changeCurrentTexture = async (url: string, type: WallType) => {
  try {
    loading.value = true

    currentTexture.value[type] = url

    if (!theme.value.modelMeta?.wallsMaterial) theme.value!.modelMeta!.wallsMaterial = {}
    const wallsMaterial = theme.value!.modelMeta!.wallsMaterial
    wallsMaterial[type] = url

    await ThemeApi.updateTheme(theme.value)

    const wall = seekByName(wallGroup, type) as Mesh
    const wallTexture = await useTexture([url])
    wallTexture.wrapS = RepeatWrapping
    wallTexture.wrapT = RepeatWrapping
    wallTexture.repeat.set(length, width)
    wall.material.map = wallTexture

    message.success('应用成功')
  } catch (e) {
    console.error(e)
    message.error('应用失败')
  } finally {
    loading.value = false
  }
}
// 默认纹理应用至当前纹理
const defaultCoverCurrentTexture = async (currentType: WallType) => {
  try {
    loading.value = true

    const wallsMaterial = theme.value?.modelMeta?.wallsMaterial
    wallsMaterial[currentType] = undefined
    await ThemeApi.updateTheme(theme.value)

    let texture = ''
    if (currentType === WallType.BOTTOM) {
      texture = defaultTexture.value.bottom
    } else if (currentType === WallType.TOP) {
      texture = defaultTexture.value.top
    } else {
      texture = defaultTexture.value.side
    }

    currentTexture.value[currentType] = texture
    const wall = seekByName(wallGroup, currentType) as Mesh
    const wallTexture = await useTexture([texture])
    wallTexture.wrapS = RepeatWrapping
    wallTexture.wrapT = RepeatWrapping
    wallTexture.repeat.set(length, width)
    wall.material.map = wallTexture

    message.success('应用成功')
  } catch (e) {
    console.error(e)
    message.error('应用失败')
  } finally {
    loading.value = false
  }
}

/** 从资源库选择 */
const resourceImgRef = ref()

const updateFunction = ref<Function>(() => {})
const updateType = ref<DefaultWallType | WallType>()
// 打开资源库
const openResourceImgDialog = (fn: Function, type: DefaultWallType | WallType) => {
  updateFunction.value = fn
  updateType.value = type
  resourceImgRef.value.open()
}

// 选择完成，执行方法
const resourceSelected = ({url}) => {
  updateFunction!.value(url, updateType.value)
}

onMounted(async () => {
  loading.value = true

  await getDefaultTexture()

  loading.value = false
})
</script>

<template>
  <el-button type="primary" @click="show = true">设置墙体纹理</el-button>

  <Dialog v-model="show" title="设置纹理" width="60%">
    <div v-loading="loading">
      <div class="text-xl mb-4">默认纹理设置</div>
      <el-form label-position="top" inline>
        <el-form-item
          v-for="(item, index) in defaultItemList"
          :key="index"
          :label="item.label"
        >
          <div class="item">
            <UploadImg
              v-model="item.data"
              :show-delete="false"
              @update:model-value="(url) => changeDefaultTexture(url, item.type)"
            />
            <el-button
              type="primary"
              @click="openResourceImgDialog(changeDefaultTexture, item.type)"
            >
              从资源库选择
            </el-button>
          </div>
        </el-form-item>
      </el-form>

      <el-divider />

      <div class="text-xl mb-4">当前纹理设置（初次使用且未保存为默认纹理）</div>
      <el-form label-position="top" inline>
        <el-form-item
          v-for="(item, index) in currentItemList"
          :key="index"
          :label="item.label"
        >
          <div class="item">
            <UploadImg
              v-model="item.data"
              :show-delete="false"
              @update:model-value="(url) => changeCurrentTexture(url, item.type)"
            />
            <el-button type="primary" @click="defaultCoverCurrentTexture(item.type)">
              应用默认纹理
            </el-button>
            <el-button
              type="primary"
              @click="openResourceImgDialog(changeCurrentTexture, item.type)"
            >
              从资源库选择
            </el-button>
          </div>
        </el-form-item>
      </el-form>
    </div>
  </Dialog>

  <ResourceContentImgSelect ref="resourceImgRef" @selected="resourceSelected" />
</template>

<style scoped lang="scss">
.item {
  display: flex;
  flex-direction: column;
  align-items: center;

  .el-button+.el-button {
    margin-left: 0;
    margin-top: 4px;
  }
}
</style>
